package com.cykj.faceledtv.netty;


import android.support.annotation.NonNull;

import com.cykj.faceledtv.BuildConfig;
import com.cykj.faceledtv.entity.NettySendMsgModel;
import com.orhanobut.logger.Logger;

import java.util.concurrent.TimeUnit;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

/**
 * Netty客户端
 *
 * @author jzh
 * @date 2018/11/06 11:05
 */
public class NettyClient {

    private static volatile NettyClient instance = null;

    private EventLoopGroup group;

    private Channel channel;
    private Bootstrap bootstrap = null;
    private ChannelFutureListener channelListener;
    private static final String IP = BuildConfig.TCP_IP;
    private static final int HOST = BuildConfig.TCP_HOST;

    public void init(@NonNull final NettyListener listener) {
        Logger.d("NettyClient init");
        group = new NioEventLoopGroup();
        bootstrap = new Bootstrap().group(group)
                .option(ChannelOption.SO_KEEPALIVE, true)
                .channel(NioSocketChannel.class)
                .handler(new NettyClientInitializer(listener));
        channelListener = new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                if (channelFuture.isSuccess()) {
                    channel = channelFuture.channel();
                    Logger.d("client连接平台成功");
                } else {
                    channel = null;
                    listener.onServiceStatusConnectChanged(NettyListener.STATUS_CONNECT_ERROR);
                    Logger.e("client连接平台失败，30s后尝试重连");
                    channelFuture.channel().eventLoop().schedule(runnable, 30, TimeUnit.SECONDS);
                }
            }
        };
    }

    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            reconnect();
        }
    };

    private NettyClient() {

    }

    public static NettyClient getInstance() {
        if (instance == null) {
            synchronized (NettyClient.class) {
                if (instance == null) {
                    instance = new NettyClient();
                }
            }
        }
        return instance;
    }

    public void connect() {
        if (channel != null && channel.isActive()) {
            Logger.d("已连接成功，无需重连");
            return;
        }
        Logger.d("---开始连接平台---");
        try {
            bootstrap.connect(IP, HOST)
                    .addListener(channelListener).sync();
        } catch (Exception e) {
            Logger.e(e, "client连接平台失败");
        }
        Logger.d("client connect out");
    }


    public void disconnect() {
        if (channel != null && channel.isActive()) {
            channel.close();
            channel = null;
        }
        Logger.d("nettyClient disconnect");
    }

    public void reconnect() {
        Logger.e("client reconnect in");
        connect();
        Logger.d("client reconnect out");
    }

    public void release() {
        disconnect();
        if (group != null) {
            group.shutdownGracefully();
            group = null;
        }
        if (bootstrap != null) {
            bootstrap = null;
        }
        Logger.d("NettyClient release");
    }

    /**
     * 发送数据
     */
    public boolean sendMsgToServer(NettySendMsgModel model, ChannelFutureListener listener) {
        if (model == null || channel == null || !channel.isActive()) {
            Logger.e("客户端发送数据失败，尚未连接到平台，拒绝发送");
            return false;
        }
        try {
            if (listener == null) {
                channel.writeAndFlush(model);
            } else {
                channel.writeAndFlush(model).addListener(listener);
            }
            Logger.d("客户端发送数据到服务端成功");
            return true;
        } catch (Exception e) {
            Logger.e(e, "客户端发送数据失败");
            return false;
        }
    }

    public void setChannel(Channel channel) {
        this.channel = channel;

    }


    public boolean getConnectStatus() {
        return channel != null && channel.isActive();
    }


}
